package com.foo.common.base.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import com.foo.common.base.annotations.JspCrud;
import com.foo.common.base.pojo.FooCrudField;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import com.google.common.base.CaseFormat;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

public enum CrudHelper {

	INSTANCE;
	private static Class<?> modelClazz = CommonCrudHelper.class;
	private static String modelUppercase = null;
	private static String actionPath = "/shop/shopBrandUser";// 记得先pull最新版本再使用本工程
	private static String jspTitleName = "品牌用户管理";// jsp模块中文名称，用于页面显示
	private static String jspFileName = "";
	private final static String global_auto_generated_directory_str = FooUtils
			.getGlobalAutoGeneratedDirectoryStr();

	private static String template_crud_java_action_mustache = "template-crud-java-action.mustache";
	private static String template_crud_jsp_mustache = "template-crud-tenmalife.jsp";// 请注意，该模板适用于tenmalife

	private final static org.slf4j.Logger logger = org.slf4j.LoggerFactory
			.getLogger(CrudHelper.class);

	public static void main(String[] args) throws Exception {

		Map<String, Object> source = CrudHelper.initCrudeDateOnClass();
		generateActionCodeWithMustache(source);
		generateJspWithMustache(source);

		// String myClassName =
		// CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL,
		// modelUppercase);
		// logger.info("{}", myClassName);
	}

	public static <T> Map<String, Object> initCrudeDateOnClass() {

		modelUppercase = modelClazz.getSimpleName();
		jspFileName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE,
				modelUppercase) + "_list.jsp";

		FooCrudField fooCrudField = new FooCrudField();
		List<FooCrudField> original_list = Lists.newArrayList();

		JspCrud crudAnnotation = null;

		// 没有crud标签会被直接排除在外
		for (Field field : modelClazz.getDeclaredFields()) {

			if (!field.isAnnotationPresent(JspCrud.class)) {
				continue;
			}

			fooCrudField = new FooCrudField();

			crudAnnotation = field.getAnnotation(JspCrud.class);
			fooCrudField.setCnName(crudAnnotation.cnName());
			fooCrudField.setDisplayOnTable(crudAnnotation.displayOnTable());
			fooCrudField.setFormFieldType(crudAnnotation.formFieldType());
			fooCrudField.setValidateOnForm(crudAnnotation.validateOnForm());

			fooCrudField.setFieldName(field.getName());
			fooCrudField
					.setFieldType(FooUtils.getJavaClassFieldTypeString(field));
			original_list.add(fooCrudField);
		}

		// 用于dataTables显示的list
		List<FooCrudField> dataTables_list = Lists.newArrayList();
		for (FooCrudField tmp : original_list) {
			if (tmp.isDisplayOnTable()) {
				dataTables_list.add(tmp);
			}
		}

		// form表单字段,存放hidden域
		List<FooCrudField> form_hidden_list = Lists.newArrayList();

		// form表单字段,存放text域
		List<FooCrudField> form_text_list_ori = Lists.newArrayList();

		for (FooCrudField tmp : original_list) {
			if (tmp.getFormFieldType().equals("hidden")) {
				form_hidden_list.add(tmp);
			} else {
				form_text_list_ori.add(tmp);
			}
		}

		// form表单字段,存放2个一组的，用于表单布局
		List<Map<String, FooCrudField>> form_text_list = Lists.newArrayList();

		// text的form为2个一组，所以需要重新构造数据结构
		Map<String, FooCrudField> form_text_list_map = Maps.newHashMap();

		List<List<FooCrudField>> partitionList = Lists
				.partition(form_text_list_ori, 2);

		for (List<FooCrudField> tmp : partitionList) {
			form_text_list_map = Maps.newHashMap();
			form_text_list_map.put("left", tmp.get(0));
			if (tmp.size() >= 2) {
				form_text_list_map.put("right", tmp.get(1));
			}
			form_text_list.add(form_text_list_map);
		}

		Map<String, Object> bean = Maps.newHashMap();

		bean.put("modelUppercase", modelUppercase);
		bean.put("modelLowerCase", CaseFormat.UPPER_CAMEL
				.to(CaseFormat.LOWER_CAMEL, modelUppercase));
		bean.put("jspTitleName", jspTitleName);
		bean.put("jspFileName", jspFileName);
		bean.put("original_list", original_list);
		bean.put("dataTables_list", dataTables_list);
		bean.put("form_hidden_list", form_hidden_list);
		bean.put("form_text_list", form_text_list);
		bean.put("form_text_list_ori", form_text_list_ori);
		bean.put("actionPath", actionPath);
		logger.info("result is :{}", bean);
		return bean;

	}

	@SuppressWarnings("unchecked")
	public static void generateActionCodeWithMustache(
			Map<String, Object> scopes) throws Exception {
		MustacheFactory mf = new DefaultMustacheFactory();

		List<FooCrudField> original_list = (List<FooCrudField>) scopes
				.get("original_list");

		List<FooCrudField> get_and_set_list = Lists.newArrayList();

		String tmpFieldName;
		String tmpFieldNameCapital;
		for (FooCrudField tmp : original_list) {
			if (tmp.getFieldName().equals("id")) {
				continue;
			}

			tmpFieldName = tmp.getFieldName();
			tmpFieldNameCapital = StringUtils.capitalize(tmp.getFieldName());

			if (tmp.getFieldType().equals("Date")) {

				tmp.setFiledGetAndSetStr("model.set" + tmpFieldNameCapital
						+ "(Strings.nullToEmpty(request.getParameter(\""
						+ tmpFieldName + "\")));");

			} else if (tmp.getFieldType().equals("int")) {

				tmp.setFiledGetAndSetStr("model.set" + tmpFieldNameCapital
						+ "(Integer.parseInt(Strings.nullToEmpty(request.getParameter(\""
						+ tmpFieldName + "\"))));");

			} else if (tmp.getFieldType().equals("String")) {
				tmp.setFiledGetAndSetStr("model.set" + tmpFieldNameCapital
						+ "(Strings.nullToEmpty(request.getParameter(\""
						+ tmpFieldName + "\")));");
			} else if (tmp.getFieldType().equalsIgnoreCase("double")) {
				tmp.setFiledGetAndSetStr("model.set" + tmpFieldNameCapital
						+ "(Double.parseDouble(Strings.nullToEmpty(request.getParameter(\""
						+ tmpFieldName + "\"))));");
			} else {
				logger.error("error type on filed:{} for type:{}", tmpFieldName,
						tmp.getFieldType());
				throw new UnsupportedOperationException(
						"error type on field:" + tmpFieldName);
			}
			get_and_set_list.add(tmp);
		}

		scopes.put("get_and_set_list", get_and_set_list);

		Mustache mustache = mf.compile(template_crud_java_action_mustache);
		Writer writer = new StringWriter();
		mustache.execute(writer, scopes);
		writer.flush();
		String result = writer.toString();
		// logger.info("result is: \n\n\n {}", result);
		//
		FooUtils.forceMkdir(global_auto_generated_directory_str);

		File resultFile = new File(global_auto_generated_directory_str + "\\"
				+ modelUppercase + "Action.java");

		IOUtils.write(result, new FileOutputStream(resultFile), "utf-8");
		logger.info("generate file:{} on path:{}", resultFile.getName(),
				global_auto_generated_directory_str);
	}

	public static void generateJspWithMustache(Map<String, Object> scopes)
			throws Exception {

		MustacheFactory mf = new DefaultMustacheFactory();

		Mustache mustache = mf.compile(template_crud_jsp_mustache);

		Writer writer = new StringWriter();

		mustache.execute(writer, scopes);
		writer.flush();

		String result = writer.toString();
		// logger.info("result is: \n\n\n {}", result);

		FooUtils.forceMkdir(global_auto_generated_directory_str);
		File resultFile = new File(
				global_auto_generated_directory_str + "\\" + jspFileName);

		IOUtils.write(result, new FileOutputStream(resultFile), "utf-8");
		logger.info("generate file:{} on path:{}", resultFile.getName(),
				global_auto_generated_directory_str);
	}

}
